/*
Copyright 2025 PerfXLab (Beijing) Technologies Co., Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "OpenSparseBLAS_func.h"
#include <cstddef>
#include <complex>


// Helper: conjugate if requested; identity for real types
template <typename T>
inline T conj_if(OpenSpB_conj_type conj, const T& v) {
    return (conj == OPENSPBLAS_CONJ) ? std::conj(v) : v;
}
template <>
inline float conj_if<float>(OpenSpB_conj_type, const float& v) {
    return v;
}
template <>
inline double conj_if<double>(OpenSpB_conj_type, const double& v) {
    return v;
}

// Generic sparse dot-product template
template <typename T>
T OpenSpB_dot(
    OpenSpB_conj_type conj,
    int nz,
    const T* x,
    const int* indx,
    const T* y,
    int incy,
    OpenSpB_base_type index_base)
{
    // if(incy <= 0) return;
    T sum{};
    const int base = (index_base == OPENSPBLAS_ONE_BASE) ? 1 : 0; 
    for (int i = 0; i < nz; ++i) {
        int idx = indx[i] - base;
        T xi = conj_if(conj, x[i]);
        sum += xi * y[idx * incy];
    }
    return sum;
}

// Public interfaces: explicit instantiation with different types
void OpenSpB_sdot(
    OpenSpB_conj_type conj, int nz,
    const float* x, const int* indx,
    const float* y, int incy,
    float* r, OpenSpB_base_type index_base
)
{
    *r = OpenSpB_dot<float>(conj, nz, x, indx, y, incy, index_base);
}

void OpenSpB_ddot(
    OpenSpB_conj_type conj, int nz,
    const double* x, const int* indx,
    const double* y, int incy,
    double* r, OpenSpB_base_type index_base
)
{
    *r = OpenSpB_dot<double>(conj, nz, x, indx, y, incy, index_base);
}

void OpenSpB_cdot(
    OpenSpB_conj_type conj, int nz,
    const void* x, const int* indx,
    const void* y, int incy,
    void* r, OpenSpB_base_type index_base
)
{
    *((std::complex<float>*)r) = OpenSpB_dot(conj, nz, (std::complex<float>*)x, indx, (std::complex<float>*)y, incy, index_base);
}

void OpenSpB_zdot(
    OpenSpB_conj_type conj, int nz,
    const void* x, const int* indx,
    const void* y, int incy,
    void* r, OpenSpB_base_type index_base
)
{
    *((std::complex<double>*)r) = OpenSpB_dot(conj, nz, (std::complex<double>*)x, indx, (std::complex<double>*)y, incy, index_base);
}